﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Collections;
using System.Reflection;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
using YWTSSys.Library;

namespace YWTSSys.Library
{
    public class CBO
    {
        #region "Private Constants"

        private const string defaultCacheByProperty = "ModuleID";
        private const int defaultCacheTimeOut = 20;
        private const string defaultPrimaryKey = "ItemID";

        private const string objectMapCacheKey = "ObjectMap_";
        private const string schemaCacheKey = "Schema_";

        #endregion

        #region "Private Shared Methods"

        #region "Object Creation/Hydration Helper Methods"
        private static bool IsNumeric(object Expression)
        {
            bool isNum;
            double retNum;
            isNum = Double.TryParse(Convert.ToString(Expression), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);
            return isNum;
        }
        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// CreateObjectFromReader creates an object of a specified type from the 
        /// provided DataReader 
        /// </summary> 
        /// <param name="objType">The type of the Object</param> 
        /// <param name="dr">The IDataReader to use to fill the object</param> 
        /// <param name="closeReader">A flag that indicates whether the DataReader should be closed</param> 
        /// <returns>The object (TObject)</returns> 
        /// <history> 
        /// [cnurse] 11/30/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static object CreateObjectFromReader(Type objType, IDataReader dr, bool closeReader)
        {
            object objObject = null;
            bool isSuccess = false;
            bool canRead = true;

            if (closeReader)
            {
                canRead = false;
                // read datareader 
                if (dr.Read())
                {
                    canRead = true;
                }
            }

            try
            {
                if (canRead)
                {
                    //Create the Object 
                    objObject = CreateObject(objType, false);

                    //hydrate the custom business object 
                    FillObjectFromReader(objObject, dr);
                }
                isSuccess = true;
            }
            finally
            {
                // Ensure DataReader is closed 
                if ((!isSuccess)) closeReader = true;
                CloseDataReader(dr, closeReader);
            }

            return objObject;
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillDictionaryFromReader fills a dictionary of objects of a specified type 
        /// from a DataReader. 
        /// </summary> 
        /// <typeparam name="TKey">The type of the key</typeparam> 
        /// <typeparam name="TValue">The type of the value</typeparam> 
        /// <param name="keyField">The key field for the object. This is used as 
        /// the key in the Dictionary.</param> 
        /// <param name="dr">The IDataReader to use to fill the objects</param> 
        /// <param name="objDictionary">The Dictionary to fill.</param> 
        /// <returns>A Dictionary of objects (T)</returns> 
        /// <history> 
        /// [cnurse] 11/30/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static IDictionary<TKey, TValue> FillDictionaryFromReader<TKey, TValue>(string keyField, IDataReader dr, IDictionary<TKey, TValue> objDictionary)
        {
            TValue objObject = default(TValue);
            TKey keyValue = default(TKey);

            try
            {
                // iterate datareader 
                while (dr.Read())
                {
                    //Create the Object 
                    objObject = (TValue)CreateObjectFromReader(typeof(TValue), dr, false);


                    //Get the value of the key field from the DataReader 
                    if (typeof(TKey).Name == "Int32" & dr[keyField].GetType().Name == "Decimal")
                    {
                        keyValue = (TKey)SetNull(dr[keyField], keyValue);
                    }
                    else if (typeof(TKey).Name.ToLower() == "string" & dr[keyField].ToString() == "dbnull")
                    {
                        keyValue = (TKey)SetNull(dr[keyField], "");
                    }
                    else
                    {
                        keyValue = (TKey)SetNull(dr[keyField], keyValue);
                    }
                }


                // add to dictionary 
                if (objObject != null)
                {
                    objDictionary[keyValue] = objObject;
                }

            }
            finally
            {
                // Ensure DataReader is closed 
                CloseDataReader(dr, true);
            }

            //Return the dictionary 
            return objDictionary;
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillListFromReader fills a list of objects of a specified type 
        /// from a DataReader 
        /// </summary> 
        /// <param name="objType">The type of the business object</param> 
        /// <param name="dr">The IDataReader to use to fill the objects</param> 
        /// <param name="objList">The List to Fill</param> 
        /// <param name="closeReader">A flag that indicates whether the DataReader should be closed</param> 
        /// <returns>A List of objects (TItem)</returns> 
        /// <remarks></remarks> 
        /// <history> 
        /// [cnurse] 11/30/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static IList FillListFromReader(Type objType, IDataReader dr, IList objList, bool closeReader)
        {
            object objObject = null;
            bool isSuccess = false;

            try
            {
                // iterate datareader 
                while (dr.Read())
                {
                    //Create the Object 
                    objObject = CreateObjectFromReader(objType, dr, false);

                    // add to collection 
                    objList.Add(objObject);
                }
                isSuccess = true;
            }
            finally
            {
                // Ensure DataReader is closed 
                if ((!isSuccess)) closeReader = true;
                CloseDataReader(dr, closeReader);
            }

            return objList;
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillListFromReader fills a list of objects of a specified type 
        /// from a DataReader 
        /// </summary> 
        /// <typeparam name="TItem">The type of the business object</typeparam> 
        /// <param name="dr">The IDataReader to use to fill the objects</param> 
        /// <param name="objList">The List to Fill</param> 
        /// <param name="closeReader">A flag that indicates whether the DataReader should be closed</param> 
        /// <returns>A List of objects (TItem)</returns> 
        /// <remarks></remarks> 
        /// <history> 
        /// [cnurse] 11/30/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static IList<TItem> FillListFromReader<TItem>(IDataReader dr, IList<TItem> objList, bool closeReader)
        {
            TItem objObject = default(TItem);
            bool isSuccess = false;

            try
            {
                // iterate datareader 
                while (dr.Read())
                {
                    //Create the Object 
                    objObject = (TItem)CreateObjectFromReader(typeof(TItem), dr, false);

                    // add to collection 
                    objList.Add(objObject);
                }
                isSuccess = true;
            }
            finally
            {
                // Ensure DataReader is closed 
                if ((!isSuccess)) closeReader = true;
                CloseDataReader(dr, closeReader);
            }

            return objList;
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillObjectFromReader fills an object from the provided DataReader. If the object 
        /// implements the IHydratable interface it will use the object's IHydratable.Fill() method. 
        /// Otherwise, it will use reflection to fill the object. 
        /// </summary> 
        /// <param name="objObject">The object to fill</param> 
        /// <param name="dr">The DataReader</param> 
        /// <history> 
        /// [cnurse] 11/30/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static void FillObjectFromReader(object objObject, IDataReader dr)
        {
            try
            {
                //Determine if object is IHydratable 
                HydrateObject(objObject, dr);
            }
            catch (IndexOutOfRangeException iex)
            {


            }
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// HydrateObject uses reflection to hydrate an object. 
        /// </summary> 
        /// <param name="objObject">The object to Hydrate</param> 
        /// <param name="dr">The IDataReader that contains the columns of data for the object</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static void HydrateObject(object objObject, IDataReader dr)
        {
            PropertyInfo objPropertyInfo = null;
            Type objPropertyType = null;
            object objDataValue = null;
            Type objDataType = default(Type);
            int intIndex = 0;

            // get cached object mapping for type 
            ObjectMappingInfo objMappingInfo = GetObjectMapping(objObject.GetType());


            // fill object with values from datareader 
            for (intIndex = 0; intIndex <= dr.FieldCount - 1; intIndex++)
            {
                //If the Column matches a Property in the Object Map's PropertyInfo Dictionary 
                if (objMappingInfo.Properties.TryGetValue(dr.GetName(intIndex).ToUpperInvariant(), out objPropertyInfo))
                {
                    //Get its type 
                    objPropertyType = objPropertyInfo.PropertyType;

                    //If property can be set 
                    if (objPropertyInfo.CanWrite)
                    {
                        //Get the Data Value from the data reader 
                        objDataValue = dr.GetValue(intIndex);

                        //Get the Data Value's type 
                        objDataType = objDataValue.GetType();

                        if (objDataValue == System.DBNull.Value)
                        {
                            // set property value to Null 
                            objPropertyInfo.SetValue(objObject, SetNull(objPropertyInfo), null);
                        }
                        else if (objPropertyType.Equals(objDataType))
                        {
                            //Property and data objects are the same type 
                            objPropertyInfo.SetValue(objObject, objDataValue, null);
                        }
                        else
                        {
                            // business object info class member data type does not match datareader member data type 
                            try
                            {
                                //need to handle enumeration conversions differently than other base types 
                                if (objPropertyType.BaseType.Equals(typeof(System.Enum)))
                                {
                                    // check if value is numeric and if not convert to integer ( supports databases like Oracle ) 
                                    if (IsNumeric(objDataValue))
                                    {
                                        objPropertyInfo.SetValue(objObject, System.Enum.ToObject(objPropertyType, Convert.ToInt32(objDataValue)), null);
                                    }
                                    else
                                    {
                                        objPropertyInfo.SetValue(objObject, System.Enum.ToObject(objPropertyType, objDataValue), null);
                                    }
                                }
                                else if (objPropertyType.FullName.Equals("System.Guid"))
                                {
                                    // guid is not a datatype common across all databases ( ie. Oracle ) 
                                    objPropertyInfo.SetValue(objObject, Convert.ChangeType(new Guid(objDataValue.ToString()), objPropertyType), null);
                                }
                                else if (objPropertyType.FullName.Equals("System.Version"))
                                {
                                    objPropertyInfo.SetValue(objObject, new Version(objDataValue.ToString()), null);
                                }
                                else
                                {
                                    // try explicit conversion 
                                    objPropertyInfo.SetValue(objObject, objDataValue, null);
                                }
                            }
                            catch
                            {
                                objPropertyInfo.SetValue(objObject, Convert.ChangeType(objDataValue, objPropertyType), null);
                            }
                        }
                    }
                }
            }
        }


        #endregion

        #region "Object Mapping Helper Methods"

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// GetCacheByProperty gets the name of the Property that the object is cached by. 
        /// For most modules this would be the "ModuleID". In the core Tabs are cached 
        /// by "PortalID" and Modules are cached by "TabID". 
        /// </summary> 
        /// <param name="objType">The type of the business object</param> 
        /// <returns>The name of the Property</returns> 
        /// <history> 
        /// [cnurse] 11/30/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static string GetCacheByProperty(Type objType)
        {
            string cacheProperty = defaultCacheByProperty;

            //check if a Cache Property Attribute has been set 
            //Dim cachePropertyAttributes As Object() = objType.GetCustomAttributes(GetType(CachePropertyAttribute), True) 
            //If (cachePropertyAttributes.Length > 0) Then 
            // Dim cachePropertyAttrib As CachePropertyAttribute = CType(cachePropertyAttributes(0), CachePropertyAttribute) 
            // cacheProperty = cachePropertyAttrib.CacheProperty 
            //End If 

            return cacheProperty;
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// GetCacheTimeOutMultiplier gets the multiplier to use in the sliding cache 
        /// expiration. This value is multiplier by the Host Performance setting, which 
        /// in turn can be set by the Host Account. 
        /// </summary> 
        /// <param name="objType">The type of the business object</param> 
        /// <returns>The timeout expiry multiplier</returns> 
        /// <history> 
        /// [cnurse] 12/01/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static int GetCacheTimeOutMultiplier(Type objType)
        {
            int cacheTimeOut = defaultCacheTimeOut;

            //'check if a Cache TimeOut Attribute has been used 
            //Dim cacheTimeOutAttributes As Object() = objType.GetCustomAttributes(GetType(CacheTimeOutAttribute), True) 
            //If (cacheTimeOutAttributes.Length > 0) Then 
            // Dim cacheTimeOutAttrib As CacheTimeOutAttribute = CType(cacheTimeOutAttributes(0), CacheTimeOutAttribute) 
            // cacheTimeOut = cacheTimeOutAttrib.TimeOut 
            //End If 

            return cacheTimeOut;
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// GetColumnName gets the name of the Database Column that maps to the property. 
        /// </summary> 
        /// <param name="objProperty">The proeprty of the business object</param> 
        /// <returns>The name of the Database Column</returns> 
        /// <history> 
        /// [cnurse] 12/02/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static string GetColumnName(PropertyInfo objProperty)
        {
            string columnName = objProperty.Name;

            //check if a ColumnName Attribute has been used 
            //Dim columnNameAttributes As Object() = objProperty.GetCustomAttributes(GetType(ColumnNameAttribute), True) 
            //If (columnNameAttributes.Length > 0) Then 
            // Dim columnNameAttrib As ColumnNameAttribute = CType(columnNameAttributes(0), ColumnNameAttribute) 
            // columnName = columnNameAttrib.ColumnName 
            //End If 

            return columnName;
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// GetObjectMapping gets an instance of the ObjectMappingInfo class for the type. 
        /// This is cached using a high priority as reflection is expensive. 
        /// </summary> 
        /// <param name="objType">The type of the business object</param> 
        /// <returns>An ObjectMappingInfo object representing the mapping for the object</returns> 
        /// <history> 
        /// [cnurse] 12/01/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static ObjectMappingInfo GetObjectMapping(Type objType)
        {
            string cacheKey = objectMapCacheKey + objType.FullName;
            ObjectMappingInfo objMap = (ObjectMappingInfo)DataCache.Instance().Get(cacheKey);

            if (objMap == null)
            {
                //Create an ObjectMappingInfo instance 
                objMap = new ObjectMappingInfo();
                objMap.ObjectType = objType.FullName;

                //Reflect on class to create Object Map 
                //objMap.CacheByProperty = GetCacheByProperty(objType) 
                //objMap.CacheTimeOutMultiplier = GetCacheTimeOutMultiplier(objType) 
                objMap.PrimaryKey = GetPrimaryKey(objType);
                objMap.TableName = GetTableName(objType);

                //Iterate through the objects properties and add each one to the ObjectMappingInfo's Properties Dictionary 
                foreach (PropertyInfo objProperty in objType.GetProperties())
                {
                    objMap.Properties.Add(objProperty.Name.ToUpperInvariant(), objProperty);
                    objMap.ColumnNames.Add(objProperty.Name.ToUpperInvariant(), GetColumnName(objProperty));
                }
                //Persist to Cache 
                DataCache.Instance().Add(cacheKey, objMap);
            }

            //Return Object Map 
            return objMap;
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// GetPrimaryKey gets the Primary Key property 
        /// </summary> 
        /// <param name="objType">The type of the business object</param> 
        /// <returns>The name of the Primary Key property</returns> 
        /// <history> 
        /// [cnurse] 12/01/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static string GetPrimaryKey(Type objType)
        {
            string primaryKey = defaultPrimaryKey;

            //First check if a TableName Attribute has been used 
            //Dim primaryKeyAttributes As Object() = objType.GetCustomAttributes(GetType(PrimaryKeyAttribute), True) 
            //If (primaryKeyAttributes.Length > 0) Then 
            // Dim primaryKeyAttrib As PrimaryKeyAttribute = CType(primaryKeyAttributes(0), PrimaryKeyAttribute) 
            // primaryKey = primaryKeyAttrib.PrimaryKey 
            //End If 

            return primaryKey;
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// GetTableName gets the name of the Database Table that maps to the object. 
        /// </summary> 
        /// <param name="objType">The type of the business object</param> 
        /// <returns>The name of the Database Table</returns> 
        /// <history> 
        /// [cnurse] 11/30/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        private static string GetTableName(Type objType)
        {
            string tableName = string.Empty;

            //'First check if a TableName Attribute has been used 
            //Dim tableNameAttributes As Object() = objType.GetCustomAttributes(GetType(TableNameAttribute), True) 
            //If (tableNameAttributes.Length > 0) Then 
            // Dim tableNameAttrib As TableNameAttribute = CType(tableNameAttributes(0), TableNameAttribute) 
            // tableName = tableNameAttrib.TableName 
            //End If 

            // If no attrubute then use Type Name 
            if (string.IsNullOrEmpty(tableName))
            {
                tableName = objType.Name;

                if (tableName.EndsWith("Info"))
                {
                    //Remove Info ending 
                    tableName.Replace("Info", string.Empty);
                }
            }

            return tableName;
        }

        #endregion

        private static XmlWriterSettings GetXmlWriterSettings(ConformanceLevel conformance)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.ConformanceLevel = conformance;
            settings.OmitXmlDeclaration = true;
            settings.Indent = true;

            return settings;
        }

        // sets a field to an application encoded null value ( used in BLL layer ) 
        public static object SetNull(PropertyInfo objPropertyInfo)
        {
            object functionReturnValue = null;
            switch (objPropertyInfo.PropertyType.ToString())
            {
                case "System.Int16":
                    functionReturnValue = -1;
                    break;
                case "System.Int32":
                case "System.Int64":
                    functionReturnValue = -1;
                    break;
                case "system.Byte":
                    functionReturnValue = 255;
                    break;
                case "System.Single":
                    functionReturnValue = Single.MinValue;
                    break;
                case "System.Double":
                    functionReturnValue = Double.MinValue;
                    break;
                case "System.Decimal":
                    functionReturnValue = Decimal.MinValue;
                    break;
                case "System.DateTime":
                    functionReturnValue = DateTime.MinValue;
                    break;
                case "System.String":
                case "System.Char":
                    functionReturnValue = "";
                    break;
                case "System.Boolean":
                    functionReturnValue = false;
                    break;
                case "System.Guid":
                    functionReturnValue = Guid.Empty;
                    break;
                default:
                    // Enumerations default to the first entry 
                    Type pType = objPropertyInfo.PropertyType;
                    if (pType.BaseType.Equals(typeof(System.Enum)))
                    {
                        System.Array objEnumValues = System.Enum.GetValues(pType);
                        Array.Sort(objEnumValues);
                        functionReturnValue = System.Enum.ToObject(pType, objEnumValues.GetValue(0));
                    }
                    else
                    {
                        // complex object 
                        functionReturnValue = null;
                    }

                    break;
            }
            return functionReturnValue;
        }

        public static object SetNull(object objValue, object objField)
        {
            object functionReturnValue = null;
            if (objValue == System.DBNull.Value)
            {
                if (objField is short)
                {
                    functionReturnValue = -1;
                }
                else if (objField is byte)
                {
                    functionReturnValue = 255;
                }
                else if (objField is int)
                {
                    functionReturnValue = -1;
                }
                else if (objField is float)
                {
                    functionReturnValue = Single.MinValue;
                }
                else if (objField is double)
                {
                    functionReturnValue = double.MinValue;
                }
                else if (objField is decimal)
                {
                    functionReturnValue = decimal.MinValue;
                }
                else if (objField is System.DateTime)
                {
                    functionReturnValue = DateTime.MinValue;
                }
                else if (objField is string)
                {
                    functionReturnValue = "";
                }
                else if (objField is bool)
                {
                    functionReturnValue = false;
                }
                else if (objField is Guid)
                {
                    functionReturnValue = Guid.Empty;
                }
                else
                {
                    // complex object 
                    functionReturnValue = null;
                }
            }
            else
            {
                // return value 
                functionReturnValue = objValue;
            }
            return functionReturnValue;
        }

        #endregion

        #region "Public Shared Methods"

        #region "Clone Object"

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// CloneObject clones an object 
        /// </summary> 
        /// <param name="objObject">The Object to Clone</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static object CloneObject(object objObject)
        {
            try
            {
                Type objType = objObject.GetType();
                object objNewObject = Activator.CreateInstance(objType);

                // get cached object mapping for type 
                ObjectMappingInfo objMappingInfo = GetObjectMapping(objType);

                foreach (KeyValuePair<string, PropertyInfo> kvp in objMappingInfo.Properties)
                {
                    PropertyInfo objProperty = kvp.Value;

                    if (objProperty.CanWrite)
                    {

                        //Check if property is ICloneable 
                        ICloneable objPropertyClone = objProperty.GetValue(objObject, null) as ICloneable;
                        if (objPropertyClone == null)
                        {
                            objProperty.SetValue(objNewObject, objProperty.GetValue(objObject, null), null);
                        }
                        else
                        {
                            objProperty.SetValue(objNewObject, objPropertyClone.Clone(), null);
                        }

                        //Check if Property is IEnumerable 
                        IEnumerable enumerable = objProperty.GetValue(objObject, null) as IEnumerable;
                        if (enumerable != null)
                        {
                            IList list = objProperty.GetValue(objNewObject, null) as IList;
                            if (list != null)
                            {
                                foreach (object obj in enumerable)
                                {
                                    list.Add(CloneObject(obj));
                                }
                            }

                            IDictionary dic = objProperty.GetValue(objNewObject, null) as IDictionary;
                            if (dic != null)
                            {
                                foreach (DictionaryEntry de in enumerable)
                                {
                                    dic.Add(de.Key, CloneObject(de.Value));
                                }
                            }
                        }
                    }
                }
                return objNewObject;
            }
            catch (Exception exc)
            {

                return null;
            }
        }

        #endregion

        #region "CloseDataReader"

        public static void CloseDataReader(IDataReader dr, bool closeReader)
        {
            // close datareader 
            if ((dr != null) && closeReader)
            {
                dr.Close();
            }
        }

        #endregion

        #region "Create Object"

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// CreateObject creates a new object of Type TObject. 
        /// </summary> 
        /// <typeparam name="TObject">The type of object to create.</typeparam> 
        /// <remarks>This overload does not initialise the object</remarks> 
        /// <history> 
        /// [cnurse] 11/30/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static TObject CreateObject<TObject>()
        {
            return (TObject)CreateObject(typeof(TObject), false);
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// CreateObject creates a new object of Type TObject. 
        /// </summary> 
        /// <typeparam name="TObject">The type of object to create.</typeparam> 
        /// <param name="initialise">A flag that indicates whether to initialise the 
        /// object.</param> 
        /// <history> 
        /// [cnurse] 11/30/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static TObject CreateObject<TObject>(bool initialise)
        {
            return (TObject)CreateObject(typeof(TObject), initialise);
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// CreateObject creates a new object. 
        /// </summary> 
        /// <param name="objType">The type of object to create.</param> 
        /// <param name="initialise">A flag that indicates whether to initialise the 
        /// object.</param> 
        /// <history> 
        /// [cnurse] 11/30/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static object CreateObject(Type objType, bool initialise)
        {
            object objObject = Activator.CreateInstance(objType);

            if (initialise)
            {
                InitializeObject(objObject);
            }

            return objObject;
        }

        #endregion

        #region "DeserializeObject"

        public static TObject DeserializeObject<TObject>(string fileName)
        {
            return DeserializeObject<TObject>(XmlReader.Create(new FileStream(fileName, FileMode.Open, FileAccess.Read)));
        }

        public static TObject DeserializeObject<TObject>(XmlDocument document)
        {
            return DeserializeObject<TObject>(XmlReader.Create(new StringReader(document.OuterXml)));
        }

        public static TObject DeserializeObject<TObject>(Stream stream)
        {
            return DeserializeObject<TObject>(XmlReader.Create(stream));
        }

        public static TObject DeserializeObject<TObject>(TextReader reader)
        {
            return DeserializeObject<TObject>(XmlReader.Create(reader));
        }

        public static TObject DeserializeObject<TObject>(XmlReader reader)
        {
            //First Create the Object 
            TObject objObject = CreateObject<TObject>(true);

            //Try to cast the Object as IXmlSerializable 
            IXmlSerializable xmlSerializableObject = objObject as IXmlSerializable;

            if (xmlSerializableObject == null)
            {
                //Use XmlSerializer 
                XmlSerializer serializer = new XmlSerializer(objObject.GetType());

                objObject = (TObject)serializer.Deserialize(reader);
            }
            else
            {
                //Use XmlReader 
                xmlSerializableObject.ReadXml(reader);
            }

            return objObject;
        }

        #endregion

        #region "FillCollection"

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillCollection fills a Collection of objects from a DataReader 
        /// </summary> 
        /// <param name="dr">The Data Reader</param> 
        /// <param name="objType">The type of the Object</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Documented 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static ArrayList FillCollection(IDataReader dr, Type objType)
        {
            return (ArrayList)FillListFromReader(objType, dr, new ArrayList(), true);
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillCollection fills a Collection of objects from a DataReader 
        /// </summary> 
        /// <param name="dr">The Data Reader</param> 
        /// <param name="objType">The type of the Object</param> 
        /// <param name="objToFill">An IList to fill</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Documented 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static IList FillCollection(IDataReader dr, Type objType, ref IList objToFill)
        {
            return FillListFromReader(objType, dr, objToFill, true);
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillCollection fills a Collection of objects from a DataReader 
        /// </summary> 
        /// <typeparam name="TItem">The type of object</typeparam> 
        /// <param name="dr">The Data Reader</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Documented 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static List<TItem> FillCollection<TItem>(IDataReader dr)
        {
            return (List<TItem>)FillListFromReader<TItem>(dr, new List<TItem>(), true);
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillCollection fills a Collection of objects from a DataReader 
        /// </summary> 
        /// <typeparam name="TItem">The type of object</typeparam> 
        /// <param name="objToFill">The List to fill</param> 
        /// <param name="dr">The Data Reader</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Documented 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static IList<TItem> FillCollection<TItem>(IDataReader dr, ref IList<TItem> objToFill)
        {
            return FillListFromReader<TItem>(dr, objToFill, true);
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillCollection fills a List of objects from a DataReader 
        /// </summary> 
        /// <typeparam name="TItem">The type of the Object</typeparam> 
        /// <param name="objToFill">The List to fill</param> 
        /// <param name="dr">The Data Reader</param> 
        /// <param name="closeReader">A flag that indicates whether the DataReader should be closed</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static IList<TItem> FillCollection<TItem>(IDataReader dr, IList<TItem> objToFill, bool closeReader)
        {
            return FillListFromReader<TItem>(dr, objToFill, closeReader);
        }

        #endregion

        #region "FillDictionary"

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillDictionary fills a Dictionary of objects from a DataReader 
        /// </summary> 
        /// <typeparam name="TKey">The key for the Dictionary</typeparam> 
        /// <typeparam name="TValue">The value for the Dictionary Item</typeparam> 
        /// <param name="keyField">The key field used for the Key</param> 
        /// <param name="dr">The Data Reader</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static Dictionary<TKey, TValue> FillDictionary<TKey, TValue>(string keyField, IDataReader dr)
        {
            return (Dictionary<TKey, TValue>)FillDictionaryFromReader<TKey, TValue>(keyField, dr, new Dictionary<TKey, TValue>());
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillDictionary fills a Dictionary of objects from a DataReader 
        /// </summary> 
        /// <typeparam name="TKey">The key for the Dictionary</typeparam> 
        /// <typeparam name="TValue">The value for the Dictionary Item</typeparam> 
        /// <param name="keyField">The key field used for the Key</param> 
        /// <param name="objDictionary">The Dictionary to fill</param> 
        /// <param name="dr">The Data Reader</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static Dictionary<TKey, TValue> FillDictionary<TKey, TValue>(string keyField, IDataReader dr, IDictionary<TKey, TValue> objDictionary)
        {
            return (Dictionary<TKey, TValue>)FillDictionaryFromReader<TKey, TValue>(keyField, dr, objDictionary);
        }

        #endregion

        #region "FillObject"

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillObject fills an object from a DataReader 
        /// </summary> 
        /// <typeparam name="TObject">The type of the object</typeparam> 
        /// <param name="dr">The Data Reader</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Documented 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static TObject FillObject<TObject>(IDataReader dr)
        {
            return (TObject)CreateObjectFromReader(typeof(TObject), dr, true);
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillObject fills an object from a DataReader 
        /// </summary> 
        /// <typeparam name="TObject">The type of the object</typeparam> 
        /// <param name="dr">The Data Reader</param> 
        /// <param name="closeReader">A flag that indicates the reader should be closed</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Documented 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static TObject FillObject<TObject>(IDataReader dr, bool closeReader)
        {
            return (TObject)CreateObjectFromReader(typeof(TObject), dr, closeReader);
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillObject fills an object from a DataReader 
        /// </summary> 
        /// <param name="dr">The Data Reader</param> 
        /// <param name="objType">The type of the object</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Documented 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static object FillObject(IDataReader dr, Type objType)
        {
            return CreateObjectFromReader(objType, dr, true);
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillObject fills an object from a DataReader 
        /// </summary> 
        /// <param name="dr">The Data Reader</param> 
        /// <param name="objType">The type of the object</param> 
        /// <param name="closeReader">A flag that indicates the reader should be closed</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Documented 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static object FillObject(IDataReader dr, Type objType, bool closeReader)
        {
            return CreateObjectFromReader(objType, dr, closeReader);
        }

        #endregion

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// FillSortedList fills a SortedList of objects from a DataReader 
        /// </summary> 
        /// <typeparam name="TKey">The key for the SortedList</typeparam> 
        /// <typeparam name="TValue">The value for the SortedList Item</typeparam> 
        /// <param name="keyField">The key field used for the Key</param> 
        /// <param name="dr">The Data Reader</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static SortedList<TKey, TValue> FillSortedList<TKey, TValue>(string keyField, IDataReader dr)
        {
            return (SortedList<TKey, TValue>)FillDictionaryFromReader<TKey, TValue>(keyField, dr, new SortedList<TKey, TValue>());
        }

        #region "GetCachedObject"

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// GetCachedObject gets an object from the Cache 
        /// </summary> 
        /// <typeparam name="TObject">The type of th object to fetch</typeparam> 
        /// <param name="cacheItemArgs">A CacheItemArgs object that provides parameters to manage the 
        /// cache AND to fetch the item if the cache has expired</param> 
        /// <param name="cacheItemExpired">A CacheItemExpiredCallback delegate that is used to repopulate 
        /// the cache if the item has expired</param> 
        /// <history> 
        /// [cnurse] 01/13/2008 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static TObject GetCachedObject<TObject>(CacheItemArgs cacheItemArgs, CacheItemExpiredCallback cacheItemExpired)
        {
            // return DataCache.GetCachedData<TObject>(cacheItemArgs, cacheItemExpired);
            return DataCache.Instance().Get<TObject>(cacheItemArgs, cacheItemExpired);
        }

        #endregion

        #region "GetProperties"

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// GetProperties gets a Dictionary of the Properties for an object 
        /// </summary> 
        /// <typeparam name="TObject">The type of the object</typeparam> 
        /// <history> 
        /// [cnurse] 01/17/2008 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static Dictionary<string, PropertyInfo> GetProperties<TObject>()
        {
            return GetObjectMapping(typeof(TObject)).Properties;
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// GetProperties gets a Dictionary of the Properties for an object 
        /// </summary> 
        /// <param name="objType">The type of the object</param> 
        /// <history> 
        /// [cnurse] 01/17/2008 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static Dictionary<string, PropertyInfo> GetProperties(Type objType)
        {
            return GetObjectMapping(objType).Properties;
        }

        #endregion

        #region "InitializeObject"

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// InitializeObject initialises all the properties of an object to their 
        /// Null Values. 
        /// </summary> 
        /// <param name="objObject">The object to Initialise</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static void InitializeObject(object objObject)
        {
            // initialize properties 
            foreach (PropertyInfo objPropertyInfo in GetObjectMapping(objObject.GetType()).Properties.Values)
            {
                if (objPropertyInfo.CanWrite)
                {
                    objPropertyInfo.SetValue(objObject, SetNull(objPropertyInfo), null);
                }
            }
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// InitializeObject initialises all the properties of an object to their 
        /// Null Values. 
        /// </summary> 
        /// <param name="objObject">The object to Initialise</param> 
        /// <param name="objType">The type of the object</param> 
        /// <history> 
        /// [cnurse] 11/29/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static object InitializeObject(object objObject, Type objType)
        {
            // initialize properties 
            foreach (PropertyInfo objPropertyInfo in GetObjectMapping(objType).Properties.Values)
            {
                if (objPropertyInfo.CanWrite)
                {
                    objPropertyInfo.SetValue(objObject, SetNull(objPropertyInfo), null);
                }
            }

            return objObject;
        }

        #endregion

        #region "SerializeObject"

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// SerializeObject serializes an Object 
        /// </summary> 
        /// <param name="objObject">The object to Initialise</param> 
        /// <param name="fileName">A filename for the resulting serialized xml</param> 
        /// <history> 
        /// [cnurse] 01/17/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static void SerializeObject(object objObject, string fileName)
        {
            using (XmlWriter writer = XmlWriter.Create(fileName, GetXmlWriterSettings(ConformanceLevel.Fragment)))
            {
                SerializeObject(objObject, writer);
                writer.Flush();
            }
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// SerializeObject serializes an Object 
        /// </summary> 
        /// <param name="objObject">The object to Initialise</param> 
        /// <param name="document">An XmlDocument to serialize to</param> 
        /// <history> 
        /// [cnurse] 01/17/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static void SerializeObject(object objObject, XmlDocument document)
        {
            StringBuilder sb = new StringBuilder();

            //Serialize the object 
            SerializeObject(objObject, XmlWriter.Create(sb, GetXmlWriterSettings(ConformanceLevel.Document)));

            //Load XmlDocument 
            document.LoadXml(sb.ToString());
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// SerializeObject serializes an Object 
        /// </summary> 
        /// <param name="objObject">The object to Initialise</param> 
        /// <param name="stream">A Stream to serialize to</param> 
        /// <history> 
        /// [cnurse] 01/17/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static void SerializeObject(object objObject, Stream stream)
        {
            using (XmlWriter writer = XmlWriter.Create(stream, GetXmlWriterSettings(ConformanceLevel.Fragment)))
            {
                SerializeObject(objObject, writer);
                writer.Flush();
            }
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// SerializeObject serializes an Object 
        /// </summary> 
        /// <param name="objObject">The object to Initialise</param> 
        /// <param name="textWriter">A TextWriter to serialize to</param> 
        /// <history> 
        /// [cnurse] 01/17/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static void SerializeObject(object objObject, TextWriter textWriter)
        {
            using (XmlWriter writer = XmlWriter.Create(textWriter, GetXmlWriterSettings(ConformanceLevel.Fragment)))
            {
                SerializeObject(objObject, writer);
                writer.Flush();
            }
        }

        /// ----------------------------------------------------------------------------- 
        /// <summary> 
        /// SerializeObject serializes an Object 
        /// </summary> 
        /// <param name="objObject">The object to Initialise</param> 
        /// <param name="writer">An XmlWriter to serialize to</param> 
        /// <history> 
        /// [cnurse] 01/17/2007 Created 
        /// </history> 
        /// ----------------------------------------------------------------------------- 
        public static void SerializeObject(object objObject, XmlWriter writer)
        {
            //Try to cast the Object as IXmlSerializable 
            IXmlSerializable xmlSerializableObject = objObject as IXmlSerializable;

            if (xmlSerializableObject == null)
            {
                //Use XmlSerializer 
                XmlSerializer serializer = new XmlSerializer(objObject.GetType());

                serializer.Serialize(writer, objObject);
            }
            else
            {
                //Use XmlWriter 
                xmlSerializableObject.WriteXml(writer);
            }
        }

        #endregion

        #endregion

    }
}
